﻿#include<iostream>
#include<array>
using namespace std;

// 静态数组
// 非类型模板参数 -- 常量
template<class T, size_t N>
class Array
{
private:
	T _a[N];
};
//int main()
//{
//	int a1[10];
//	array<int, 10>a2;
//	array<int, 100>a3;
//	//和c的静态数组很相似 那么array的意义在哪里
//	//对于越界的检查
//	//a1[15] = 0;
//	cout << a1[10] << endl;
//	cout << a1[11] << endl;//越界写是通过抽查的方式进行
//	//array 都会报错
//	//cout << a2[10] << endl;
//	//cout << a2[11] << endl;//由于11 大于 size_t n 在底层实现的时候先会进行大小的判断
//
//	//但是其实这个初衷并没有得到执行 因为c的数组实在是方便简洁 习惯很难改变
//	
//	return 0;
//}



//template<class T,size_t N>//通常不传浮点型
//void Func(const T& x)
//{
//	cout << N << endl;
//}
//int main()
//{
//	int N = 100;
//	Func<int, 100>(1);
//	return 0;
//}

///////////////////////////////////////////////////////////////////////////////////////////////////////
class Date
{
public:
	Date(int year = 1900, int month = 1, int day = 1)
		: _year(year)
		, _month(month)
		, _day(day)
	{}
	bool operator<(const Date& d)const
	{
		return (_year < d._year) ||
			(_year == d._year && _month < d._month) ||
			(_year == d._year && _month == d._month && _day < d._day);
	}
	bool operator>(const Date& d)const
	{
		return (_year > d._year) ||
			(_year == d._year && _month > d._month) ||
			(_year == d._year && _month == d._month && _day > d._day);
	}
	friend ostream& operator<<(ostream& _cout, const Date& d)
	{
		_cout << d._year << "-" << d._month << "-" << d._day;
		return _cout;
	}
private:
	int _year;
	int _month;
	int _day;
};
// 函数模板 -- 参数匹配
template<class T>
bool Less(T left, T right)
{
	return left < right;
}

// 针对某些类型进行特殊处理 -- Date*
template<>
bool Less<Date*>(Date* left, Date* right)
{
	return *left < *right;
}
//  期望对Date* 进行特殊处理 利用函数模板特化
//	template<> 也可以不写 因为函数存在函数重载问题
//	但是类模板就不可以这样操作了
//bool Less(Date* left, Date* right)
//{
//	return *left < *right;
//}

//int main()
//{
//	cout << Less(1, 2) << endl;   // 可以比较，结果正确
//
//	Date d1(2022, 7, 7);
//	Date d2(2022, 7, 8);
//	cout << Less(d1, d2) << endl;  // 可以比较，结果正确
//
//	Date* p1 = &d1;
//	Date* p2 = &d2;
//	cout << Less(p1, p2) << endl;  // 可以比较，结果错误
//
//	return 0;
//}

///////////////////////////////////////////////////////////////////////////////////////////////////////
//类模板的特化
template<class T1, class T2>
class Data
{
public:
	Data() { cout << "Data<T1, T2>" << endl; }
private:
	T1 _d1;
	T2 _d2;
};

// 全特化
template<>
class Data<double, char>
{
public:
	Data() { cout << "Data<double, char>" << endl; }
};

// 半特化、偏特化
template<class T1>
class Data<T1, char>
{
public:
	Data() { cout << "Data<T1, char>" << endl; }
};

// 参数类型进一步限制
template<class T1, class T2>
class Data<T1*, T2*>
{
public:
	Data() { cout << "Data<T1*, T2*>" << endl; }
};

template<class T1, class T2>
class Data<T1&, T2&>
{
public:
	Data() { cout << "Data<T1&, T2&>" << endl; }
};

//int main()
//{
//	Data<int, int> d1;
//	Data<double, double> d2;
//	Data<double, char> d3;
//	Data<char, char> d4;
//
//	Data<char*, char*> d5;
//	Data<char, int*> d6;
//	Data<double*, int*> d7;
//
//	Data<double&, int&> d8;
//
//	return 0;
//1. 全特化（外卖：没有模板参数了）
//2. 半特化 （外卖+家里面自己的大米） 理所当然 当全部符合的时候 全特化比半特化优先级更好
//3.没有成品和半成品 就只能自己做了 const T 
//4.但凡是指针 就会调用有指针的 指针就相当于蛋白质 只要妈妈煮好了就必须让你吃
//5.和指针类似 引用也是妈妈煮好就必须食用的操作 
//}





//知识点的补充说明：
//int main()
//{
//	
//	//日期类指针就是特化的一个小小的使用场景
//	//沉住气 暑假吃过的亏不要重蹈覆辙 马上就要进入进阶了 昨天的优先级队列 得补
//	//声明和定义分离 
//	return 0;
//}


//综上所述-->特化的本质：编译器的参数匹配原则  

//模板不要像函数一样 声明放在.h 操作放在.cpp 模板一定不要分离编译 放在一个文件下就是最完美的
//具体原因 我觉得是 主函数使用的时候是A<int>a1; 但是这种形式无论在那个文件都是没有对应样子的 你比如说函数 他fuc（）... 在主函数中也是func()... 模板不会是这样对应完整的


//【优点】
//1. 模板复用了代码，节省资源，更快的迭代开发，C++的标准模板库(STL)因此而产生
//2. 增强了代码的灵活性
//【缺陷】
//1. 模板会导致代码膨胀问题，也会导致编译时间变长
//2. 出现模板编译错误时，错误信息非常凌乱，不易定位错误



////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//在实际运用中一般使用都是public继承，几乎很少使用protetced / private继承，也不提倡
//使用protetced / private继承，因为protetced / private继承下来的成员都只能在派生类的类里
//面使用，实际中扩展维护性不强
//class Person
//{
//public:
//	void Print()
//	{
//		cout << "name:" << _name << endl;
//		cout << "age:" << _age << endl;
//	}
//protected:
//	string _name = "peter"; // 姓名
//	int _age = 18; //年龄
//};
//// 继承后父类的Person的成员（成员函数+成员变量）都会变成子类的一部分
////Student和Teacher复用了Person的成员。。
//class Student : public Person //student 叫做派生类
//{
//protected:
//	int _stuid; // 学号
//};
//
//class Teacher : public Person
//{
//protected:
//	int _jobid; // 工号
//};
////private 这个在本质上就是不可见的 protected 他除了在继承中有所差异（基类中的成员可以传给派生类） 和private没有区别
//int main()
//{
//	Student s;
//	Teacher t;
//	s.Print();
//	t.Print();
//	return 0;
//}


//以后谈论继承 都默认公有继承
//派生类对象 可以赋值给 基类的对象 / 基类的指针 / 基类的引用 被称为切割 切片 

//int main()
//{
//	Person p;
//	Student s;
//	p = s;//父子关系赋值 中间不存在类型转换 即不存在临时变量（强制类型转换和隐式类型转换都混存在临时变量）
//
//	Person& rp = s;//这个不会报错
//
//
//	int i = 1;
//	double d = 2.2;
//	i = d;//临时变量的类型是int类型
//
//	const int& ri = d ;// 当类型不匹配的时候 ri不是直接做d的引用 而是先找到临时变量 这个临时变量是int型 但是临时变量是具有常性的 所以得加上const
//	return 0;
//}

//class Person
//{
//protected:
//	string _name = "小李子"; // 姓名
//	int _num = 111; 	   // 身份证号
//};
//
//class Student : public Person
//{
//public:
//	void Print()
//	{
//		cout << " 姓名:" << _name << endl;
//		cout << " 学号:" << _num<< endl;
//		cout << " 身份证号:" << Person::_num << endl;
//	}
//protected:
//	int _num = 999; // 学号
//};

// 两个func什么关系
// 重载  重写  重定义/隐藏  编译报错
// ->重定义/隐藏 
// 父类和子类的同名成员函数，函数名相同就构成隐藏
//class A
//{
//public:
//	void fun()
//	{
//		cout << "A::func()" << endl;
//	}
//};
//class B : public A
//{
//public:
//	void fun(int i)
//	{
//		cout << "B::func(int i)->" << i << endl;
//	}
//};
//
//void Test()
//{
//	B b;
//	b.fun(10);
//};

/////////////////////////////////////////////////
// 编译报错
//class A
//{
//public:
//	void fun()
//	{
//		cout << "A::func()" << endl;
//	}
//};
//class B : public A
//{
//public:
//	void fun(int i)
//	{
//		cout << "B::func(int i)->" << i << endl;
//	}
//};
//
//void Test()
//{
//	B b;
//	//b.fun();
//	b.A::fun();
//};
//
//int main()
//{
//	Test();
//
//	return 0;
//}

class Person
{
public:
	Person(const char* name)
		: _name(name)
	{
		cout << "Person()" << endl;
	}

	Person(const Person& p)
		: _name(p._name)
	{
		cout << "Person(const Person& p)" << endl;
	}

	Person& operator=(const Person& p)
	{
		cout << "Person operator=(const Person& p)" << endl;
		if (this != &p)// this 代表的是地址
			_name = p._name;

		return *this;
	}

	~Person()
	{
		cout << "~Person()" << endl;
	}
protected:
	string _name; // 姓名
};

// 派生类中
// 1、构造函数，父类成员调用父类的构造函数完成初始化
class Student : public Person
{
public:
	Student(const char* name, int num)
		:Person(name)
		, _num(num)
	{}

	Student(const Student& s)
		:Person(s)//这里虽然Person想要的是Person(const Person& p) 但是赋值存在切片问题 赋值:派生类给基类赋值
		, _num(s._num)
	{}

	Student& operator=(const Student& s)
	{
		if (this != &s)
		{
			Person::operator=(s);//这里为什么要加Person 如果不写的话 由于函数名字相同就会发生隐藏 会一直调用自己的operator 导致 stack overflow
			_num = s._num;
		}

		return *this;
	}

protected:
	int _num; //学号
};

int main()
{
	Student s1("张三", 18);
	Student s2(s1);

	Student s3("李四", 20);

	s1 = s3;


	return 0;
}